# ----------------------------------------------------------------------------
#       Copyright (C) 2013-2014 Huynh Vi Lam  <domovilam@gmail.com>
#
#       This file is part of pimucha.
#
#	This program is free software: you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation, either version 3 of the License, or
#	(at your option) any later version.
#	
#	This program is distributed in the hope that it will be useful,
#	but WITHOUT ANY WARRANTY; without even the implied warranty of
#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#	GNU General Public License for more details.
#	
#	You should have received a copy of the GNU General Public License
#	along with this program.  If not, see <http://www.gnu.org/licenses/>.
# ----------------------------------------------------------------------------



import logging,select,socket,sys,threading

logger = logging.getLogger()

if sys.hexversion > 0x030000F0:
    import queue as Queue
else:
    import Queue
INPUTq = Queue.Queue()
QEmpty = Queue.Empty

from  piHAlibs import (addr2host)


class TCPRXServer(object):
    def __init__(self,addr=None):
        self.host,self.port = addr2host(defaddr=('0.0.0.0','11000'),addr=addr)
        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server.setblocking(0)
        self.type = 'SRV'
        self.name = 'TCPRXServer'
        self.evtnetq = Queue.Queue()
        self.servercmds = {'STARTS':self.starts,'STOPS':self.stops}
        self.inputs = [self.server]
        self.outputs = []
        self.cnxqueues = {}
        self.setup = False
        self.stop = False
 
    def tsetup(self):
        try:
            self.server.bind((self.host,self.port))
            self.server.listen(5)
            self.setup = True
        except:
            pass

    def closecnx(self,s):
        if s in self.outputs:
            self.outputs.remove(s)
        if s in self.inputs:
            self.inputs.remove(s)
        s.close()
        del self.cnxqueues[s]

    def addevt(self,evt,evtq):
        if isinstance(evt,bytes):
            evtq.put(evt + b"\n")
        else:
            evtq.put((evt + "\n").encode('utf-8'))

    def starts(self):
        tt = threading.Thread(target=self.serve)
        tt.name = 'TCPRXServer_' + self.name
        tt.daemon = True
        tt.start()
        print ('TCPRXServer started and active...')

    def serve(self):
        print ('Listening at address %s on port number %s...\n' % (self.host, self.port))
        while not self.stop:
            try:
                evt = self.evtnetq.get()
            except QEmpty:
                evt = None
            if evt:
                logger.debug("Getting evt from queue %s ", repr(evt))
                for q in self.cnxqueues:
                    if isinstance(evt,list):
                        for e in evt:
                            self.addevt(e,self.cnxqueues[q])
                    else:
                        self.addevt(evt,self.cnxqueues[q])

            readable, writable, exceptional = select.select(self.inputs, self.outputs, self.inputs)
            for s in readable:
                if s is self.server:
                    cnx, caddr = s.accept()
                    logger.debug("New connection from %s", caddr)
                    cnx.setblocking(0)
                    self.inputs.append(cnx)
                    self.outputs.append(cnx)
                    self.cnxqueues.setdefault(cnx)
                    self.cnxqueues[cnx] = Queue.Queue()
                else:
                    try:
                        data = s.recv(1024)
                        caddr = s.getpeername()
                    except Exception as e:	#disconnected
                        logger.error("%s : %s", repr(e.__class__), str(e))
                        data = b'QUIT'
                    if data != b"" :
                        logger.debug('Receiving "%s" from %s',data,caddr)
                    if data.upper() == b'QUIT':
                        self.closecnx(s)
            for s in writable:
                if s not in self.outputs: break
                try:
                    next_msg = self.cnxqueues[s].get()
                    s.send(next_msg)                   
                except QEmpty:
                    pass
            for s in exceptional:
                self.closecnx(s)

    def stops(self):
        for s in self.outputs:
            self.closecnx(s)
        self.server.close()
        self.stop = True
        print ('TCPRXServer shutting down...')

